package org.teremail.message.builder;

import java.util.ArrayList;
import java.util.List;

import org.teremail.message.ContentHeaders;
import org.teremail.message.Entity;
import org.teremail.message.MessageHeaders;
import org.teremail.message.MultipartMessage;

import com.google.common.collect.Lists;

public class MultipartMessageBuilder implements MultipartBuilder, MessageBuilder {
    
    private final List<EntityBuilder> partBuilders;
    private MultipartMessage orginalMessage;
    private final MessageHeadersBuilder headersBuilder;
    private String preamble;
    private String epilogue;
    private boolean hasChanged = true;
    private String id;
    private ContentHeadersBuilder contentHeadersBuilder;


    public MultipartMessageBuilder(MessageHeadersBuilder headersBuilder, 
            List<EntityBuilder> partBuilders, 
            ContentHeadersBuilder contentHeadersBuilder) {
        this.headersBuilder = headersBuilder;
        this.partBuilders = partBuilders;
        this.contentHeadersBuilder = contentHeadersBuilder;            
    }
    
    public MultipartMessageBuilder(MessageHeadersBuilder headersBuilder, 
            ContentHeadersBuilder contentHeadersBuilder) {
        this(headersBuilder, new ArrayList<EntityBuilder>(), 
                contentHeadersBuilder);            
    }
    
    public MultipartMessageBuilder() {
        this(new MessageHeadersBuilder(), new ArrayList<EntityBuilder>(), 
                new ContentHeadersBuilder());
    }

    public MultipartMessageBuilder(MultipartMessage message,
            List<EntityBuilder> partBuilders) {
        this(new MessageHeadersBuilder(message.getHeader()), partBuilders, 
                new ContentHeadersBuilder(message.getContentHeader()));
        this.orginalMessage = message;
        this.epilogue = orginalMessage.getEpilogue();
        this.preamble = orginalMessage.getPreamble();
        hasChanged = false;
    }
    
    public MultipartMessageBuilder setId(String id) {
        this.id = id;
        hasChanged = true;
        return this;
    }
    
    public String getId() {
        return id;
    }

    public MultipartMessageBuilder setPreamble(String preamble) {
        hasChanged = true;
        this.preamble = preamble;
        return this;
    }

    public MultipartMessageBuilder setEpilogue(String epilogue) {
        this.epilogue = epilogue;
        return this;
    }

    public SimpleEntityBuilder addSimpleEntity() {
        SimpleEntityBuilder b = new SimpleEntityBuilder();
        partBuilders.add(b);
        return b;
    }

    public SimpleEntityBuilder addSimpleEntity(String type, String subType) {
        SimpleEntityBuilder b = new SimpleEntityBuilder(type, subType);
        partBuilders.add(b);
        return b;
    }

    public MultipartMessage build() {
        if (hasChanged()) {
            MessageHeaders header = headersBuilder.build();
            ContentHeaders contentHeader = contentHeadersBuilder.build();
            List<Entity> parts = Lists.newArrayList();
            for (EntityBuilder eb : partBuilders) {
                parts.add(eb.build());
            }
            return new MultipartMessage(id, contentHeader, header, preamble, 
                    parts, epilogue);
        } else {
            return orginalMessage;
        }
    }
    
    public boolean hasChanged() {
        return hasChanged || orginalMessage == null 
            || headersBuilder.hasChanged()
            || contentHeadersBuilder.hasChanged()
            || childPartChanged();
    }
    
    private boolean childPartChanged() {
        for (EntityBuilder eb : partBuilders) {
            if (eb.hasChanged()) {
                return true;
            }
        }
        return false;
    }
    
    public MessageHeadersBuilder getHeaderBuilder() {
        return headersBuilder;
    }

    public MultipartMessageBuilder clearParts() {
        partBuilders.clear();
        hasChanged = true;
        return this;
    }

    public MultipartMessageBuilder addEntityBuilder(EntityBuilder entityBuilder) {
        partBuilders.add(entityBuilder);
        hasChanged = true;
        return this;
    }

    public void setHeaders(String messageHeaders) {
        headersBuilder.load(messageHeaders);
    }

    public boolean isMultipart() {
        return true;
    }

    public void setContentHeaders(String contentHeaders) {
        contentHeadersBuilder.load(contentHeaders);
    }

}
